﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using YellowMap.Resources;
using Microsoft.Devices.Sensors;
using YellowMap.View.Page;

namespace YellowMap
{
    public class GoogleServiceHandler
    {
        public event Action<List<Place>> OnGetPlace;
        public event Action<Detail> OnGetDetail;
        public event Action<int, double, double> OnGetGeocodingLocation;
        public event Action<GoogleDirectionResponse> OnGetDirection;
        //private string[] searchIDClosetBestRated = {"travel_Airport", "travel_CarRental", "travel_Hotel","entertainment_Atraction", "entertainment_Museum", "entertainment_Spa", 
        //                                             "shopping_Outlet", "education_University"};
        private List<string> searchIDClosetBestRated = new List<string> {"travel_Airport", "travel_CarRental", "travel_Hotel","entertainment_Atraction", "entertainment_Museum", "entertainment_Spa", 
                                                     "shopping_Outlet", "education_University" };
        /// <summary>
        /// Send request to get Direction
        /// </summary>
        /// <param name="fromLat"></param>
        /// <param name="fromLng"></param>
        /// <param name="toLat"></param>
        /// <param name="toLng"></param>
        public void GetDirection(double fromLat, double fromLng, double toLat, double toLng)
        {
            WebClient client = new WebClient();
            client.DownloadStringCompleted += GetDirection_DownloadStringCompleted;


            GoogleDirectionRequest request = new GoogleDirectionRequest();
            request.Unit = GoogleDirectionRequest.DistanceUnit.Mile;
            request.SetStartEnd(fromLat, fromLng, toLat, toLng);

            if (AppViewModel.Instance.SettingVM.Language == "Vi")
            {
                request.Unit = GoogleDirectionRequest.DistanceUnit.Km;
                request.Language = GoogleDirectionRequest.DisplayLanguage.VIETNAMESE;
            }
            else
            {
                request.Unit = GoogleDirectionRequest.DistanceUnit.Mile;
                request.Language = GoogleDirectionRequest.DisplayLanguage.ENGLISH;
            }
            client.DownloadStringAsync(new Uri(request.ToString()));
        }

        /// <summary>
        ///  Call back function after get direction
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void GetDirection_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                if (AppViewModel.Instance.SettingVM.Language == "Vi")
                    MainPage.Instance.Toast(LangVi.errorGetDirection);
                else
                {
                    MainPage.Instance.Toast(LangEn.errorGetDirection);
                }
                MainPage.Instance.HideWaiting();
                return;
            }
            else
            {
                GoogleDirectionResponse response = GoogleDirectionResponse.ParseFromJSON(e.Result);
                OnGetDirection(response);
            }
        }

        /// <summary>
        /// Send request to get location by address
        /// </summary>
        /// <param name="address"></param>
        public void GetLocationByAddress(string address)
        {
            WebClient client = new WebClient();
            client.DownloadStringCompleted += GetLocation_DownloadStringCompleted;
            GoogleGeocodeLocationRequest request = new GoogleGeocodeLocationRequest();
            request.Address = address;
            client.DownloadStringAsync(new Uri(request.ToString()));
        }

        void GetLocation_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                if (AppViewModel.Instance.SettingVM.Language == "Vi")
                    MainPage.Instance.Toast(LangVi.errorGetLocation);
                else
                {
                    MainPage.Instance.Toast(LangEn.errorGetLocation);
                }
                return;
            }
            else
            {
                GoogleGeocodeLocationResponse response = GoogleGeocodeLocationResponse.ParseFromJSON(e.Result);
                int countResult = response.Results.Count;
                if (countResult == 0)
                {
                    OnGetGeocodingLocation(0, 0, 0);
                    return;
                }

                OnGetGeocodingLocation(countResult, response.Results[0].Geometry.Location.Latitude, response.Results[0].Geometry.Location.Longtitude);
            }
        }

        /// <summary>
        /// Send request to get place detail by place info
        /// </summary>
        /// <param name="p"></param>
        public async void GetDetail(Place p)
        {
            var detail = await DBHelper.GetDetail(p);
            if (detail != null)
            {
                OnGetDetail(detail);
                return;
            }
            WebClient client = new WebClient();
            client.DownloadStringCompleted += GetDetail_DownloadStringCompleted;

            GooglePlaceDetailRequest request = new GooglePlaceDetailRequest();
            request.Reference = p.ReferenceId;
            client.DownloadStringAsync(new Uri(request.ToString()));
        }

        /// <summary>
        /// Call back function after get place detail
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void GetDetail_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                if (AppViewModel.Instance.SettingVM.Language == "Vi")
                    MainPage.Instance.Toast(LangVi.errorGetDetail);
                else
                {
                    MainPage.Instance.Toast(LangEn.errorGetDetail);
                }
                return;
            }

            if (e.Result == null)
            {
                OnGetDetail(null);
                return;
            }

            Detail detail = new Detail();

            GooglePlaceDetailResponse response = GooglePlaceDetailResponse.ParseFromJSON(e.Result);
            if (response.Result == null)
            {
                OnGetDetail(null);
                return;
            }
            detail.Name = response.Result.Name;
            detail.Address = response.Result.FormattedAddress;
            detail.Image = response.Result.Icon;
            detail.Id = response.Result.Id;
            detail.FormatedPhoneNumber = response.Result.FormattedPhoneNumber;
            detail.InternationalPhoneNumber = response.Result.InternationalPhoneNumber;
            // Save Database
            DBHelper.InsertDetail(detail);

            OnGetDetail(detail);
        }

        /// <summary>
        /// Send request to get place by favorite place
        /// </summary>
        /// <param name="favorite"></param>
        public void GetPlace(Favorite favorite)
        {
            WebClient client = new WebClient();
            client.DownloadStringCompleted += GetPlace_DownloadStringCompleted;

            GooglePlaceRequest request = new GooglePlaceRequest();
            request.Radius = Constant.DEFAULT_SETTING_RADIUS;
            string subCate = favorite.SubCate;
            SUBCATE = subCate;
            string[] types = null;
            string[] keywords = null;
            #region Get type & keyword
            foreach (var cate in AppViewModel.Instance.Categories)
            {
                foreach (var sub in cate.SubCategories)
                {
                    if (sub.Id == subCate)
                    {
                        types = sub.Type.Split(new string[] { "|", "+", ",", " " }, StringSplitOptions.RemoveEmptyEntries);
                        keywords = sub.Keyword.Split(new string[] { "|", "+", ",", " " }, StringSplitOptions.RemoveEmptyEntries);
                    }
                }
            }
            #endregion

            #region Add type & keyword
            foreach (var item in types)
            {
                request.AddTypes(item);
            }

            foreach (var item in keywords)
            {
                request.AddKeyWords(item);
            }
            #endregion

            #region Search by
            if (AppViewModel.Instance.SettingVM.SearchBy == Constant.SEARCHBY_BESTRATE)
            {
                request.Rankby = RankByEnum.prominence;
            }
            else
            {
                request.Rankby = RankByEnum.distance;
            }
            #endregion

            #region Search from
            if (AppViewModel.Instance.SettingVM.SearchFrom == Constant.SEARCHFROM_CHOOSEONMAP)
            {
                request.Lattitude = MainPage.Instance.CenterLocation.Latitude;
                request.Longtitude = MainPage.Instance.CenterLocation.Longitude;
            }
            else
            {
                request.Lattitude = AppViewModel.Instance.SettingVM.UserLocationLattitude;
                request.Longtitude = AppViewModel.Instance.SettingVM.UserLocationLongitude;
            }
            #endregion

            #region Add name

            request.LocationName = favorite.Name;

            #endregion

            Debug.WriteLine(request);
            lastSearchQuery = request.ToString();
            SoLanGuiRequest = 0;
            client.DownloadStringAsync(new Uri(request.ToString()));
        }

        /// <summary>
        /// Send request to get place by history place
        /// </summary>
        /// <param name="history"></param>
        public void GetPlace(History history)
        {
            WebClient client = new WebClient();
            client.DownloadStringCompleted += GetPlace_DownloadStringCompleted;

            GooglePlaceRequest request = new GooglePlaceRequest();
            request.Radius = Constant.DEFAULT_SETTING_RADIUS;
            string subCate = history.SubCate;
            SUBCATE = subCate;
            string[] types = null;
            string[] keywords = null;
            #region Get type & keyword
            foreach (var cate in AppViewModel.Instance.Categories)
            {
                foreach (var sub in cate.SubCategories)
                {
                    if (sub.Id == subCate)
                    {
                        types = sub.Type.Split(new string[] { "|", "+", ",", " " }, StringSplitOptions.RemoveEmptyEntries);
                        keywords = sub.Keyword.Split(new string[] { "|", "+", ",", " " }, StringSplitOptions.RemoveEmptyEntries);
                    }
                }
            }
            #endregion

            #region Add type & keyword
            foreach (var item in types)
            {
                request.AddTypes(item);
            }

            foreach (var item in keywords)
            {
                request.AddKeyWords(item);
            }
            #endregion

            #region Search by
            if (AppViewModel.Instance.SettingVM.SearchBy == Constant.SEARCHBY_BESTRATE)
            {
                request.Rankby = RankByEnum.prominence;
            }
            else
            {
                request.Rankby = RankByEnum.distance;
            }
            #endregion

            #region Search from
            if (AppViewModel.Instance.SettingVM.SearchFrom == Constant.SEARCHFROM_CHOOSEONMAP)
            {
                request.Lattitude = MainPage.Instance.CenterLocation.Latitude;
                request.Longtitude = MainPage.Instance.CenterLocation.Longitude;
            }
            else
            {
                request.Lattitude = AppViewModel.Instance.SettingVM.UserLocationLattitude;
                request.Longtitude = AppViewModel.Instance.SettingVM.UserLocationLongitude;
            }
            #endregion

            #region Add name

            request.LocationName = history.Name;

            #endregion

            Debug.WriteLine(request);
            lastSearchQuery = request.ToString();
            SoLanGuiRequest = 0;
            client.DownloadStringAsync(new Uri(request.ToString()));
        }



        static bool isTurnOnEasternEgg = false;
        /// <summary>
        /// Send request to get places by keyword
        /// </summary>
        /// <param name="name">keyword</param>
        /// <param name="mySubCate">subcateId</param>
        public void GetPlace(string name = "", string mySubCate = "")
        {

            switch (name)
            {
                case ">>on":
                    {
                        isTurnOnEasternEgg = true;
                        return;
                        break;
                    }

                case ">>off":
                    {
                        isTurnOnEasternEgg = false;
                        return;
                        break;
                    }
                default:
                    break;
            }
            GooglePlaceRequest request = new GooglePlaceRequest();
            request.Radius = Constant.DEFAULT_SETTING_RADIUS;
            string subCate = AppViewModel.Instance.SettingVM.SubCate;
            if (mySubCate != "")
            {
                subCate = mySubCate;
            }
            SUBCATE = subCate;
            string[] types = null;
            string[] keywords = null;

            #region Get type & keyword
            string subID = ""; //[pkhuy] used for 5 special cases (searching by best rated and closest are the same
            foreach (var cate in AppViewModel.Instance.Categories)
            {
                foreach (var sub in cate.SubCategories)
                {
                    if (sub.Id == subCate)
                    {
                        types = sub.Type.Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries);
                        keywords = sub.Keyword.Split(new string[] { "+" }, StringSplitOptions.RemoveEmptyEntries);
                        subID = sub.Id;
                        break;
                    }
                }
            }
            #endregion

            #region Add type & keyword
            foreach (var item in types)
            {
                request.AddTypes(item);
            }

            foreach (var item in keywords)
            {
                request.AddKeyWords(item);
            }
            #endregion
            #region Search by
            if (AppViewModel.Instance.SettingVM.SearchBy == Constant.SEARCHBY_BESTRATE || searchIDClosetBestRated.IndexOf(subID) > -1)
            {
                request.Rankby = RankByEnum.prominence;
            }
            else
            {
                request.Rankby = RankByEnum.distance;
            }
            #endregion

            #region Search from
            if (AppViewModel.Instance.SettingVM.SearchFrom == Constant.SEARCHFROM_CHOOSEONMAP)
            {
                //[pkhuy] fix Toan's issue
                //if (SearchPage.isSetting)
                //{
                //    request.Lattitude = 32.892613;
                //    request.Longtitude = -117.194174;
                //    AppViewModel.Instance.SettingVM.MapLattitude = request.Lattitude;
                //    AppViewModel.Instance.SettingVM.MapLongitude = request.Longtitude;
                //    SearchPage.isSetting = false;
                //}
                //else
                //{
                //    if (MainPage.Instance.CenterLocation.Latitude == 0 && MainPage.Instance.CenterLocation.Longitude == 98.867777)
                //    {
                //        request.Lattitude = AppViewModel.Instance.SettingVM.MapLattitude;
                //        request.Longtitude = AppViewModel.Instance.SettingVM.MapLongitude;
                //    }
                //    else
                //    {
                //        request.Lattitude = MainPage.Instance.CenterLocation.Latitude;
                //        request.Longtitude = MainPage.Instance.CenterLocation.Longitude;
                //        AppViewModel.Instance.SettingVM.MapLattitude = request.Lattitude;
                //        AppViewModel.Instance.SettingVM.MapLongitude = request.Longtitude;
                //    }
                //}

                request.Lattitude = AppViewModel.Instance.SettingVM.MapLattitude;
                request.Longtitude = AppViewModel.Instance.SettingVM.MapLongitude;
            }
            else
            {
                //if (AppViewModel.Instance.SettingVM.UserLocationLattitude == 0 && AppViewModel.Instance.SettingVM.UserLocationLongitude == 0)
                //{
                //    if (AppViewModel.Instance.SettingVM.Language == "Vi")
                //    {
                //        MainPage.Instance.Toast(LangVi.errorGetGPS);
                //    }
                //    else
                //    {
                //        MainPage.Instance.Toast(LangEn.errorGetGPS);
                //    }
                //    MainPage.Instance.HideWaiting();
                //    return;
                //}
                //else
                //{
                request.Lattitude = AppViewModel.Instance.SettingVM.UserLocationLattitude;
                request.Longtitude = AppViewModel.Instance.SettingVM.UserLocationLongitude;
                //}
            }
            #endregion

            request.LocationName = name;
            if (isTurnOnEasternEgg)
            {
                request.Lattitude = 32.892613;
                request.Longtitude = -117.194174;
            }
            WebClient client = new WebClient();
            client.DownloadStringCompleted += GetPlace_DownloadStringCompleted;





            Debug.WriteLine(request);

            lastSearchQuery = request.ToString();
            SoLanGuiRequest = 0;
            client.DownloadStringAsync(new Uri(request.ToString()));
        }


        public string SplitKeyWord(string keyword)
        {
            string newkeyword_1st = "";
            string newkeyword_2nd = "";
            newkeyword_1st = keyword.Replace('-', ' ');
            newkeyword_2nd = newkeyword_1st.Replace('_', ' ');
            return newkeyword_2nd;
        }

        public void GetPlaceByKeyWord(string name = "")
        {
            string name_new = SplitKeyWord(name);
            SUBCATE = "";
            switch (name_new)
            {
                case ">>on":
                    {
                        isTurnOnEasternEgg = true;
                        return;
                        break;
                    }

                case ">>off":
                    {
                        isTurnOnEasternEgg = false;
                        return;
                        break;
                    }
                default:
                    break;
            }
            GooglePlaceRequest request = new GooglePlaceRequest();
            request.Radius = Constant.DEFAULT_SETTING_RADIUS;
            string subID = ""; //[pkhuy] used for 5 special cases (searching by best rated and closest are the same
            #region Search by
            if (AppViewModel.Instance.SettingVM.SearchBy == Constant.SEARCHBY_BESTRATE || searchIDClosetBestRated.IndexOf(subID) > -1)
            {
                request.Rankby = RankByEnum.prominence;
            }
            else
            {
                request.Rankby = RankByEnum.distance;
            }
            #endregion

            #region Search from
            if (AppViewModel.Instance.SettingVM.SearchFrom == Constant.SEARCHFROM_CHOOSEONMAP)
            {
                request.Lattitude = MainPage.Instance.CenterLocation.Latitude;
                request.Longtitude = MainPage.Instance.CenterLocation.Longitude;
            }
            else
            {
                //if (AppViewModel.Instance.SettingVM.UserLocationLattitude == 0 && AppViewModel.Instance.SettingVM.UserLocationLongitude == 0)
                //{
                //    if (AppViewModel.Instance.SettingVM.Language == "Vi")
                //    {
                //        MainPage.Instance.Toast(LangVi.errorGetGPS);
                //    }
                //    else
                //    {
                //        MainPage.Instance.Toast(LangEn.errorGetGPS);
                //    }
                //    MainPage.Instance.HideWaiting();
                //    return;
                //}
                //else
                //{
                request.Lattitude = AppViewModel.Instance.SettingVM.UserLocationLattitude;
                request.Longtitude = AppViewModel.Instance.SettingVM.UserLocationLongitude;
                //}
            }

            //if (AppViewModel.Instance.SettingVM.SearchFrom == Constant.SEARCHFROM_CHOOSEONMAP)
            //{
            //    request.Lattitude = AppViewModel.Instance.SettingVM.MapLattitude;
            //    request.Longtitude = AppViewModel.Instance.SettingVM.MapLongitude;
            //}
            //else
            //{
            //    request.Lattitude = AppViewModel.Instance.SettingVM.UserLocationLattitude;
            //    request.Longtitude = AppViewModel.Instance.SettingVM.UserLocationLongitude;               
            //}

            #endregion

            request.LocationName = name_new;
            if (isTurnOnEasternEgg)
            {
                request.Lattitude = 32.892613;
                request.Longtitude = -117.194174;
            }
            WebClient client = new WebClient();
            client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(GetPlace_DownloadStringCompleted);


            //string subCate = AppViewModel.Instance.SettingVM.SubCate;
            //string[] types = null;
            //string keywords = name;

            #region Get type & keyword

            //foreach (var cate in AppViewModel.Instance.Categories)
            //{
            //    foreach (var sub in cate.SubCategories)
            //    {
            //        if (sub.Id == subCate)
            //        {
            //            types = sub.Type.Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries);
            //            keywords = sub.Keyword.Split(new string[] { "+" }, StringSplitOptions.RemoveEmptyEntries);
            //            subID = sub.Id;
            //            break;
            //        }
            //    }
            //}
            #endregion

            #region Add type & keyword
            //foreach (var item in types)
            //{
            //    request.AddTypes(item);
            //}

            //foreach (var item in keywords)
            //{
            //    request.AddKeyWords(item);
            //}
            #endregion




            Debug.WriteLine(request);

            lastSearchQuery = request.ToString();
            SoLanGuiRequest = 0;
            client.DownloadStringAsync(new Uri(request.ToString()));
        }
        static string SUBCATE = "";
        string lastSearchQuery = "";
        int SoLanGuiRequest = 0;

        /// <summary>
        /// Call back function after get place from google service
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        async void GetPlace_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {

            if (e.Error != null)
            {
                if (e.Error.ToString().Contains("System.Exception: Metadata file is invalid or corrupted."))
                {
                    if (AppViewModel.Instance.SettingVM.Language == "Vi")
                        MainPage.Instance.Toast(LangVi.str_nolocation);
                    else
                    {
                        MainPage.Instance.Toast(LangEn.str_nolocation);
                    }
                    return;
                }
                //else if (e.Error.Message == "The remote server returned an error: NotFound.")
                //{
                //    if (AppViewModel.Instance.SettingVM.Language == "Vi")
                //        MainPage.Instance.Toast(LangVi.str_nolocation);
                //    else
                //    {
                //        MainPage.Instance.Toast(LangEn.str_nolocation);
                //    }
                //    return;
                //}

                //if (App.isJustActive)
                //{
                //    App.isJustActive = false;
                //    return;
                //}
                if (AppViewModel.Instance.SettingVM.Language == "Vi")
                    MainPage.Instance.Toast(LangVi.errorGetPlace);
                else
                {
                    MainPage.Instance.Toast(LangEn.errorGetPlace);
                }
                return;
            }
            GooglePlaceRespond response = GooglePlaceRespond.ParseFromJSON(e.Result);
            List<Place> places = new List<Place>();



            SoLanGuiRequest++;
            foreach (var p in response.Places)
            {
                Place place = new Place();
                place.Address = p.Address;
                place.Lattitude = p.Geometry.Location.Lattitude;
                place.Longitude = p.Geometry.Location.Longitude;
                place.Name = p.Name;
                place.PlaceId = p.Id;
                place.ReferenceId = p.ReferenceId;
                place.SubCate = SUBCATE;
                places.Add(place);

            }


            if (SoLanGuiRequest == 1)
            {
                Debug.WriteLine("KETQUA1= " + places.Count);
                PrintPlaceName(places);
                OnGetPlace(places);
            }
            else
            {
                Debug.WriteLine("KETQUA TIEPTHEO= " + places.Count);
                PrintPlaceName(places);
                MainPage.Instance.ShowNextPlace(places);
            }
            /*
            if (response.NextPageToken != null)
            {
                MainPage.Instance.ShowWaiting();
                WebClient client = new WebClient();
                client.DownloadStringCompleted += GetPlace_DownloadStringCompleted;
                string nextQuery = lastSearchQuery + "&pagetoken=" + response.NextPageToken;
                Debug.WriteLine("Next Query = " + nextQuery);
                await Task.Delay(1500);
                client.DownloadStringAsync(new Uri(nextQuery));
            }
            */
        }


        async Task PrintPlaceName(List<Place> places)
        {
            foreach (var p in places)
            {
                Debug.WriteLine("PLACE NAME: " + p.Name);
            }
        }
    }
}
